/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.sunrise.entity;

import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import static javax.persistence.CascadeType.ALL;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.*;
import org.apache.commons.lang.WordUtils;

/**
 *
 * @author frank
 */
@Entity
@Table(name="Users")
@NamedQueries({
        @NamedQuery(name = User.findById, query = "SELECT u FROM User u WHERE u.id = :id"),
        @NamedQuery(name = User.findByEmail, query = "SELECT u FROM User u WHERE u.email = :email"),
        @NamedQuery(name = User.search, query = "SELECT u FROM User u WHERE CONCAT(u.name, ' ', u.surname, ' ', u.email, ' ', u.city) LIKE :query AND u.id <> :ownId"),
        @NamedQuery(name = User.searchUsersWithPublicCal, 
                query = "SELECT u FROM User u INNER JOIN Calendar c on u=c.owner WHERE CONCAT(u.name, ' ', u.surname, ' ', u.email, ' ', u.city) LIKE :query AND u.id <> :ownId AND c.publicCalendar = 1")
})
public class User implements Serializable {    
    private static final long serialVersionUID = 1L;
    public static final String findById = "User.findById";
    public static final String findByEmail = "User.findByEmail";
    public static final String search = "User.search";
    public static final String searchUsersWithPublicCal = "User.searchUsersWithPublicCal";
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    
    @Size(min=1,max=255, message = "Name cannot be empty")
    @Column(nullable=false)
    private String name;
    
    @Size(min=1,max=255, message = "Surname cannot be empty")
    @Column(nullable=false)
    private String surname;
    
    @Column(nullable=false, unique=true)
    private String email;
    
    @Size(min=6,max=255, message = "Password should be at least 6 characters long")
    @Column(nullable=false)
    private String password;
    
    private String groupName;
    
    @OneToMany(cascade=ALL, mappedBy = "owner")
    private List<Calendar> calendars;
    
    @OneToMany(mappedBy = "recipient")
    private List<InvitationRequest> invitationRequests;
    
    @OneToMany(mappedBy = "recipient")
    private List<WeatherAlert> weatherAlerts;
    
    // optional fields
    private char gender;

    private String address;

    private String city;

    private String country;
    
    private boolean emailEnabled;
    
    public User () {
    
    }
    
    public User (String name, String surname, String email, String password) {
        this.name = name;
        this.surname = surname;
        this.email = email;
        this.password = password;
        this.groupName = "USER";
    }
    
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * @return the surname
     */
    public String getSurname() {
        return surname;
    }

    /**
     * @param surname the surname to set
     */
    public void setSurname(String surname) {
        this.surname = surname;
    }

    public String getFullName() {
        return WordUtils.capitalize(name + " " + surname);
    }
    
    /**
     * @return the email
     */
    public String getEmail() {
        return email;
    }

    /**
     * @param email the email to set
     */
    public void setEmail(String email) {
        this.email = email;
    }

    /**
     * @return the password
     */
    public String getPassword() {
        return password;
    }

    /**
     * @param password the password to set
     */ 
    public void setPassword(String password) {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] hash = digest.digest(password.getBytes("UTF-8"));
            BigInteger bigInt = new BigInteger(1, hash);
            this.password = bigInt.toString(16);
//            StringBuilder hexString = new StringBuilder();
//            for (int i = 0; i < hash.length; i++) {
//                hexString.append(Integer.toHexString(0xFF & hash[i]));
//            }
//            this.password = hexString.toString();
        } catch (NoSuchAlgorithmException | UnsupportedEncodingException ex) {
            Logger.getLogger(User.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    public void setGroupName(String groupName) {
        this.groupName = groupName;
    }

    public String getGroupName() {
        return groupName;
    }
    
    
    /**
     * @return the calendars
     */
    public List<Calendar> getCalendars() {
        if(calendars == null)
            calendars = new ArrayList<Calendar>();
        return calendars;
    }

    public void setCalendars(List<Calendar> calendars) {
        if(calendars == null)
            calendars = new ArrayList<Calendar>();
        this.calendars = calendars;
    }
    
    public void addCalendar(Calendar calendar) {
        if(calendars == null)
            calendars = new ArrayList<Calendar>();
        this.calendars.add(calendar);
    }
    
    /**
     * @return the invitationRequests
     */
    public List<InvitationRequest> getInvitationRequests() {
        if(invitationRequests == null)
            invitationRequests = new ArrayList<InvitationRequest>();
        return invitationRequests;
    }

    public void setInvitationRequests(List<InvitationRequest> invitationRequests) {
        if(invitationRequests == null)
            invitationRequests = new ArrayList<InvitationRequest>();
        this.invitationRequests = invitationRequests;
    }
    
    public void addInvitationRequest(InvitationRequest invitationRequest) {
        if(invitationRequests == null)
            invitationRequests = new ArrayList<InvitationRequest>();
        this.invitationRequests.add(invitationRequest);
    }
    
    public List<WeatherAlert> getWeatherAlerts() {
        if(weatherAlerts == null)
            weatherAlerts = new ArrayList<WeatherAlert>();
        return weatherAlerts;
    }
    
    /**
     * @return the gender
     */
    public char getGender() {
        return gender;
    }

    /**
     * @param gender the gender to set
     */
    public void setGender(char gender) {
        this.gender = gender;
    }

    /**
     * @return the address
     */
    public String getAddress() {
        return address;
    }

    /**
     * @param address the address to set
     */
    public void setAddress(String address) {
        this.address = address;
    }

    /**
     * @return the city
     */
    public String getCity() {
        return city;
    }

    /**
     * @param city the city to set
     */
    public void setCity(String city) {
        this.city = city;
    }

    /**
     * @return the country
     */
    public String getCountry() {
        return country;
    }

    /**
     * @param country the country to set
     */
    public void setCountry(String country) {
        this.country = country;
    }

    public boolean isEmailEnabled() {
        return emailEnabled;
    }

    public void setEmailEnabled(boolean emailEnabled) {
        this.emailEnabled = emailEnabled;
    }
    
    @Override
    public int hashCode() {
        int hash = 0;
        hash += (getId() != null ? getId().hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof User)) {
            return false;
        }
        User other = (User) object;
        if ((this.getId() == null && other.getId() != null) || (this.getId() != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "com.sunrise.entity.User[ id=" + getId() + " ]";
    }
}
